package org.zjvis.datascience.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zjvis.datascience.common.algo.BaseAlg;
import org.zjvis.datascience.common.dto.FolderDTO;
import org.zjvis.datascience.common.dto.MLModelDTO;
import org.zjvis.datascience.common.dto.ModelLocalDTO;
import org.zjvis.datascience.common.dto.PanelDTO;
import org.zjvis.datascience.common.enums.*;
import org.zjvis.datascience.common.etl.BaseETL;
import org.zjvis.datascience.common.model.TaskItems;
import org.zjvis.datascience.common.model.TaskMeta;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.common.util.ToolUtil;
import org.zjvis.datascience.common.vo.MLModelVO;
import org.zjvis.datascience.common.vo.project.ProjectNameVO;
import org.zjvis.datascience.service.mapper.ModelLocalMapper;
import org.zjvis.datascience.service.mapper.ProjectMapper;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * @description Panel 右侧算子面板加载 Service
 * @date 2021-12-28
 */
@Service
public class PanelService {

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private ModelLocalMapper modelLocalMapper;

    @Autowired
    private ModelLocalService modelLocalService;

    @Autowired
    private MLModelService mlModelService;

    @Autowired
    private FolderService folderService;

    private static List<String> algNames = new ArrayList<>();

    private static List<String> algorithmNames = new ArrayList<>();

    private static List<String> etls = new ArrayList<>();

    private static List<String> featureEngAlgo = new ArrayList<>();

    private static Map<String, String> urlHelpers = new HashMap<>();

    static {
        etls.add("Filter");
        etls.add("Join");
        etls.add("Sample");
        etls.add("Sql");
        etls.add("Union");
        etls.add("PivotTable");
        etls.add("imputation_stat");
        etls.add("imputation_multi");
        etls.add("anomaly_stat");
        etls.add("anomaly_knn");
    }

    static {
        featureEngAlgo.add("standardization");
        featureEngAlgo.add("timeseries_decompose");
        featureEngAlgo.add("smoothing");
    }

    static {
        algNames.add("dbscan");
        algNames.add("kmeans");
        algNames.add("pca");
        algNames.add("tsne");
    }

    static {
        algorithmNames.add("new_kmeans");
        algorithmNames.add("new_dbscan");
        algorithmNames.add("new_pca");
        algorithmNames.add("new_tsne");
        algorithmNames.add("new_lle");
        algorithmNames.add("new_iso_forest");
        algorithmNames.add("new_fp_growth");
        algorithmNames.add("new_prefix_span");
        algorithmNames.add("new_arima");
        algorithmNames.add("new_holt_winters");
        algorithmNames.add("new_shift");
        algorithmNames.add("new_adf");
    }


    static {
        /*
         *算子库
         */
        //聚类DBSCAN
        urlHelpers.put("dbscan", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=dbscan");
        //聚类K-means
        urlHelpers.put("kmeans", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=k-means");

        // 新版-聚类K-means
        urlHelpers.put("new_kmeans", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_kmeans");
        // 新版-聚类DBSCAN
        urlHelpers.put("new_dbscan", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_dbscan");
        // 新版-降维-PCA
        urlHelpers.put("new_pca", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_pca");
        // 新版-降维-TSNE
        urlHelpers.put("new_tsne", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_tsne");
        // 新版-LLE
        urlHelpers.put("new_lle", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_lle");
        // 新版-孤立森林异常值检测
        urlHelpers.put("new_iso_forest", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_iso_forest");
        // 新版-FP-Growth
        urlHelpers.put("new_fp_growth", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_fp_growth");
        // 新版-PrefixSpan
        urlHelpers.put("new_prefix_span", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_prefix_span");
        // 新版-ARIMA
        urlHelpers.put("new_arima", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_arima");
        // 新版-HOLT_WINTERS
        urlHelpers.put("new_holt_winters", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_holt_winters");
        // 新版-Shift
        urlHelpers.put("new_shift", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_shift");
        // 新版-ADF
        urlHelpers.put("new_adf", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=new_adf");

        //降维-PCA
        urlHelpers.put("pca", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=pca");
        //降维-TSNE
        urlHelpers.put("tsne", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=tsne");
        //ETL/清洗 Filter
        urlHelpers.put("Filter", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=%e2%91%a0-filter");
        //ETL/清洗 Join
        urlHelpers.put("Join", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=%e2%91%a0-join");
        //ETL/清洗 Sample
        urlHelpers.put("Sample", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=%e2%91%a1-sample");
        //ETL/清洗 SQL
        urlHelpers.put("Sql", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=_3%e3%80%81sql%e6%94%af%e6%8c%81");
        //ETL/清洗 Union
        urlHelpers.put("Union", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=%e2%91%a1-union");
        //ETL/清洗 清洗
        urlHelpers.put("Clean", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=%e6%95%b0%e6%8d%ae%e6%b8%85%e6%b4%97");
        //图构建
        urlHelpers.put("Graph", "https://nebula-inner.lab.zjvis.net/docs/#/graph_network");

        /*
        经济7步算子
         */
        urlHelpers.put("imputation_stat", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=_4%e3%80%81-%e7%bc%ba%e5%a4%b1%e5%80%bc%e6%8f%92%e8%a1%a5");
        urlHelpers.put("imputation_multi", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=_4%e3%80%81-%e7%bc%ba%e5%a4%b1%e5%80%bc%e6%8f%92%e8%a1%a5");
        urlHelpers.put("anomaly_stat", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=%e5%bc%82%e5%b8%b8%e5%80%bc%e6%a3%80%e6%b5%8b-%e7%bb%9f%e8%ae%a1");
        urlHelpers.put("anomaly_knn", "https://nebula-inner.lab.zjvis.net/docs/#/formula_guide?id=%e5%bc%82%e5%b8%b8%e5%80%bc%e6%a3%80%e6%b5%8b-%e8%bf%91%e9%82%bb");
        urlHelpers.put("standardization", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=_1%e3%80%81%e6%a0%87%e5%87%86%e5%8c%96");
        urlHelpers.put("timeseries_decompose", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=_2%e3%80%81%e6%97%b6%e9%97%b4%e5%ba%8f%e5%88%97%e5%88%86%e8%a7%a3");
        urlHelpers.put("smoothing", "https://nebula-inner.lab.zjvis.net/docs/#/data_clean?id=_3%e3%80%81%e6%95%b0%e6%8d%ae%e5%b9%b3%e6%bb%91");
    }

    private boolean isContainKey(String name, String searchKey) {
        String lowerName = name.toLowerCase();
        String lowerKey = searchKey.toLowerCase();
        return lowerName.contains(lowerKey);
    }

    private TaskMeta loadJLAB(PanelDTO panelDTO, String searchKey, List<TaskMeta> taskMetas) {

        TaskMeta taskMeta = new TaskMeta("自定义算子(new)", TaskTypeEnum.TASK_TYPE_JLAB.getVal()
                , SubTypeEnum.SELF_DEFINE.getVal(), 1, false, 1L, false, null);

        if (StringUtils.isEmpty(searchKey) || isContainKey("自定义算子(new)", searchKey)) {
            if (StringUtils.isNotEmpty(searchKey)) {
                taskMeta.setHighLight(true);
            }

            taskMetas.add(taskMeta);
            panelDTO.add(taskMeta);
        }
        return taskMeta;
    }

    private TaskMeta loadJHUB(PanelDTO panelDTO, String searchKey, List<TaskMeta> taskMetas) {

        TaskMeta taskMeta = new TaskMeta("自定义算子(new)", TaskTypeEnum.TASK_TYPE_JLHUB.getVal()
                , SubTypeEnum.SELF_DEFINE.getVal(), 1, false, 1L, false, null);

        if (StringUtils.isEmpty(searchKey) || isContainKey("自定义算子(new)", searchKey)) {
            if (StringUtils.isNotEmpty(searchKey)) {
                taskMeta.setHighLight(true);
            }

            taskMetas.add(taskMeta);
            panelDTO.add(taskMeta);
        }
        return taskMeta;
    }

    public JSONArray getTemplateParamList(String fileName) {
        String json = new ToolUtil().readJsonFile(fileName);
        if (json.length() == 0) {
            return null;
        }
        return JSONArray.parseArray(json);
    }

    /**
     * 新版算法模块展示信息
     *
     * @param panelDTO
     * @param searchKey
     * @param type
     * @param projectId
     * @return
     */
    private PanelDTO loadAlgorithmModel(PanelDTO panelDTO, String searchKey, Long type, Long projectId) {
        TaskItems taskItems = new TaskItems();
        List<TaskMeta> taskMetaList = new ArrayList<>();
        int subType = 0;
        Long userId = JwtUtil.getCurrentUserId();
        if (type == 1L) {
            taskItems.setName(SubTypeEnum.NEW_ALGORITHM_LOADED.getDesc());
            subType = SubTypeEnum.NEW_ALGORITHM_LOADED.getVal();

            if (StringUtils.isEmpty(searchKey) || isContainKey("自定义算子", searchKey)) {
                this.loadJHUB(panelDTO, searchKey, taskMetaList);
            }

            for (String algorithm : algorithmNames) {
                TaskMeta taskMeta;
                String displayName;
                int algType;
                int taskType;
                AlgPyEnum alg = AlgPyEnum.getEnumByName(algorithm);
                displayName = alg.getDesc();
                taskType = TaskTypeEnum.TASK_TYPE_ALGOPY.getVal();
                algType = alg.getVal();
                if (StringUtils.isEmpty(searchKey) || isContainKey(displayName, searchKey)) {
                    taskMeta = new TaskMeta(displayName,
                            taskType, SubTypeEnum.GENERAL_ALGORITHM.getVal(), algType
                            , false, 0L, false, urlHelpers.get(algorithm));
                    if (StringUtils.isNotEmpty(searchKey)) {
                        taskMeta.setHighLight(true);
                    }
                    taskMetaList.add(taskMeta);
                    panelDTO.add(taskMeta);
                }
            }
        } else {
            taskItems.setName(SubTypeEnum.MODEL_LOADED.getDesc());
            subType = SubTypeEnum.MODEL_LOADED.getVal();
        }

        JSONObject projInfo = new JSONObject();
        projInfo.put("projectId", projectId);
        projInfo.put("userId", userId);
        projInfo.put("type", type);

        MLModelVO modelvo = new MLModelVO();
        modelvo.setProjectId(projectId);
        modelvo.setUserId(userId);
        List<FolderDTO> folderDTOS = folderService.getFolders(modelvo);
        for (FolderDTO folder : folderDTOS) {
            if (folder.getSubType() == subType) {
                Long folderId = folder.getId();
                List<ModelLocalDTO> modelsInFolder = modelLocalMapper.queryByFolderId(folderId);
                //无搜索或搜索到文件夹后，加入所有文件夹内部模型
                if (StringUtils.isEmpty(searchKey) || isContainKey(folder.getName(), searchKey)) {
                    List<TaskMeta> modelInFolder = new ArrayList<>();
                    Integer unfold = 0;
                    if (modelsInFolder != null) {
                        for (ModelLocalDTO model : modelsInFolder) {
                            String modelName = model.getName();
                            TaskMeta folderModelTaskMeta = new TaskMeta(modelName, TaskTypeEnum.TASK_TYPE_AM.getVal(),
                                    subType, modelLocalService.fieldToInt(model.getField()), false, model.getId()
                                    , false, model.getResource());
                            if (StringUtils.isNotEmpty(searchKey) && isContainKey(modelName, searchKey)) {
                                unfold = 1;
                                folderModelTaskMeta.setHighLight(true);
                            }
                            if (StringUtils.isEmpty(searchKey)) {
                                panelDTO.add(folderModelTaskMeta);
                            }
                            modelInFolder.add(folderModelTaskMeta);
                        }
                    }
                    TaskMeta singleFolderTaskMeta = new TaskMeta(folder.getName(),
                            TaskTypeEnum.TASK_TYPE_AM.getVal(), subType, -1,
                            true, new Long(folder.getId()), true, "",
                            Math.toIntExact(folder.getUnfold()), modelInFolder);
                    if (StringUtils.isNotEmpty(searchKey) && isContainKey(folder.getName(), searchKey)) {
                        singleFolderTaskMeta.setHighLight(true);
                    }
                    singleFolderTaskMeta.setUnfold(unfold);
                    taskMetaList.add(singleFolderTaskMeta);
                    panelDTO.add(singleFolderTaskMeta);
                } else {//如果有搜索key且没有与文件夹名相匹配，则尝试匹配文件夹内部模型名称
                    boolean hasModelMatched = false;
                    List<TaskMeta> modelInFolder = new ArrayList<>();
                    if (modelsInFolder != null) {
                        for (ModelLocalDTO model : modelsInFolder) {
                            String modelName = model.getName();
                            if (isContainKey(modelName, searchKey)) {
                                TaskMeta folderModelTaskMeta = new TaskMeta(modelName, TaskTypeEnum.TASK_TYPE_AM.getVal(),
                                        subType, modelLocalService.fieldToInt(model.getField()), false, model.getId()
                                        , false, model.getResource());
                                folderModelTaskMeta.setHighLight(true);
                                modelInFolder.add(folderModelTaskMeta);
                                panelDTO.add(folderModelTaskMeta);
                                hasModelMatched = true;
                            }
                        }
                    }
                    if (hasModelMatched) {
                        TaskMeta singleFolderTaskMeta = new TaskMeta(folder.getName(),
                                TaskTypeEnum.TASK_TYPE_AM.getVal(), subType, -1,
                                true, new Long(folder.getId()), true, "",
                                Math.toIntExact(folder.getUnfold()), modelInFolder);
                        singleFolderTaskMeta.setUnfold(1);
                        taskMetaList.add(singleFolderTaskMeta);
                        panelDTO.add(singleFolderTaskMeta);
                    }
                }
            }
        }
        taskItems.setItems(taskMetaList);
        taskItems.setSubType(subType);
        panelDTO.add(taskItems);
        return panelDTO;
    }

    private PanelDTO loadAlgoModel(PanelDTO panelDTO, String searchKey, Long type, Long projectId) {
        TaskItems AMItems = new TaskItems();
        List<TaskMeta> AMTaskMetas = new ArrayList<>();
        int subType = 0;
        Long userId = JwtUtil.getCurrentUserId();
        if (type == 1L) {
            AMItems.setName(SubTypeEnum.AlGORITHM_LOADED.getDesc());
            subType = SubTypeEnum.AlGORITHM_LOADED.getVal();

            if (StringUtils.isEmpty(searchKey) || isContainKey("自定义算子", searchKey)) {
                //this.loadJLAB(panelDTO, searchKey, AMTaskMetas);
                this.loadJHUB(panelDTO, searchKey, AMTaskMetas);
            }

            for (String algName : algNames) {
                TaskMeta taskMeta;
                String displayName;
                int algType;
                int taskType;
                AlgPyEnum alg = AlgPyEnum.getEnumByName(algName);
                displayName = alg.getDesc();
                taskType = TaskTypeEnum.TASK_TYPE_ALGOPY.getVal();
                algType = alg.getVal();
                if (StringUtils.isEmpty(searchKey) || isContainKey(displayName, searchKey)) {
                    taskMeta = new TaskMeta(displayName,
                            taskType, SubTypeEnum.GENERAL_ALGORITHM.getVal(), algType
                            , false, 0L, false, urlHelpers.get(algName));
                    if (StringUtils.isNotEmpty(searchKey)) {
                        taskMeta.setHighLight(true);
                    }
                    AMTaskMetas.add(taskMeta);
                    panelDTO.add(taskMeta);
                }
            }
        } else {
            AMItems.setName(SubTypeEnum.MODEL_LOADED.getDesc());
            subType = SubTypeEnum.MODEL_LOADED.getVal();
        }

        JSONObject projInfo = new JSONObject();
        projInfo.put("projectId", projectId);
        projInfo.put("userId", userId);
        projInfo.put("type", type);
        List<ModelLocalDTO> modelLocalDTOS = modelLocalMapper.getAMLoaded(projInfo);

        for (ModelLocalDTO model : modelLocalDTOS) {
            String displayName = model.getName();
            if (StringUtils.isEmpty(searchKey) || isContainKey(displayName, searchKey)) {
                //todo model.getModelDesc <--> url
                TaskMeta taskMeta = new TaskMeta(displayName, TaskTypeEnum.TASK_TYPE_AM.getVal(),
                        subType, modelLocalService.fieldToInt(model.getField()), false, model.getId()
                        , false, model.getResource());
                if (StringUtils.isNotEmpty(searchKey) && isContainKey(displayName, searchKey)) {
                    taskMeta.setHighLight(true);
                }
                AMTaskMetas.add(taskMeta);
                panelDTO.add(taskMeta);
            }
        }

        MLModelVO modelvo = new MLModelVO();
        modelvo.setProjectId(projectId);
        modelvo.setUserId(userId);
        List<FolderDTO> folderDTOS = folderService.getFolders(modelvo);
        for (FolderDTO folder : folderDTOS) {
            if (folder.getSubType() == subType) {
                Long folderId = folder.getId();
                List<ModelLocalDTO> modelsInFolder = modelLocalMapper.queryByFolderId(folderId);
                //无搜索或搜索到文件夹后，加入所有文件夹内部模型
                if (StringUtils.isEmpty(searchKey) || isContainKey(folder.getName(), searchKey)) {
                    List<TaskMeta> modelInFolder = new ArrayList<>();
                    Integer unfold = 0;
                    if (modelsInFolder != null) {
                        for (ModelLocalDTO model : modelsInFolder) {
                            String modelName = model.getName();
                            TaskMeta folderModelTaskMeta = new TaskMeta(modelName, TaskTypeEnum.TASK_TYPE_AM.getVal(),
                                    subType, modelLocalService.fieldToInt(model.getField()), false, model.getId()
                                    , false, model.getResource());
                            if (StringUtils.isNotEmpty(searchKey) && isContainKey(modelName, searchKey)) {
                                unfold = 1;
                                folderModelTaskMeta.setHighLight(true);
                            }
                            if (StringUtils.isEmpty(searchKey)) {
                                panelDTO.add(folderModelTaskMeta);
                            }
                            modelInFolder.add(folderModelTaskMeta);
                        }
                    }
                    TaskMeta singleFolderTaskMeta = new TaskMeta(folder.getName(),
                            TaskTypeEnum.TASK_TYPE_AM.getVal(), subType, -1,
                            true, new Long(folder.getId()), true, "",
                            Math.toIntExact(folder.getUnfold()), modelInFolder);
                    if (StringUtils.isNotEmpty(searchKey) && isContainKey(folder.getName(), searchKey)) {
                        singleFolderTaskMeta.setHighLight(true);
                    }
                    singleFolderTaskMeta.setUnfold(unfold);
                    AMTaskMetas.add(singleFolderTaskMeta);
                    panelDTO.add(singleFolderTaskMeta);
                } else {//如果有搜索key且没有与文件夹名相匹配，则尝试匹配文件夹内部模型名称
                    boolean hasModelMatched = false;
                    List<TaskMeta> modelInFolder = new ArrayList<>();
                    if (modelsInFolder != null) {
                        for (ModelLocalDTO model : modelsInFolder) {
                            String modelName = model.getName();
                            if (isContainKey(modelName, searchKey)) {
                                TaskMeta folderModelTaskMeta = new TaskMeta(modelName, TaskTypeEnum.TASK_TYPE_AM.getVal(),
                                        subType, modelLocalService.fieldToInt(model.getField()), false, model.getId()
                                        , false, model.getResource());
                                folderModelTaskMeta.setHighLight(true);
                                modelInFolder.add(folderModelTaskMeta);
                                panelDTO.add(folderModelTaskMeta);
                                hasModelMatched = true;
                            }
                        }
                    }
                    if (hasModelMatched) {
                        TaskMeta singleFolderTaskMeta = new TaskMeta(folder.getName(),
                                TaskTypeEnum.TASK_TYPE_AM.getVal(), subType, -1,
                                true, new Long(folder.getId()), true, "",
                                Math.toIntExact(folder.getUnfold()), modelInFolder);
                        singleFolderTaskMeta.setUnfold(1);
                        AMTaskMetas.add(singleFolderTaskMeta);
                        panelDTO.add(singleFolderTaskMeta);
                    }
                }
            }
        }
        AMItems.setItems(AMTaskMetas);
        AMItems.setSubType(subType);
        panelDTO.add(AMItems);
        return panelDTO;
    }


    private PanelDTO loadFeatureEngAlgo(PanelDTO panelDTO, String searchKey) {
        TaskItems featureTaskItems = new TaskItems();
        featureTaskItems.setName(SubTypeEnum.FEATURE_ENGINEERING.getDesc());
        List<TaskMeta> featureTaskMetas = new ArrayList<>();
        for (String featureTask : featureEngAlgo) {
            String displayName = AlgPyEnum.getEnumByName(featureTask).getDesc();
            if (StringUtils.isEmpty(searchKey) || isContainKey(displayName, searchKey)) {
                TaskMeta taskMeta = new TaskMeta(displayName, TaskTypeEnum.TASK_TYPE_ALGOPY.getVal(),
                        SubTypeEnum.FEATURE_ENGINEERING.getVal(), AlgPyEnum.getEnumByDesc(displayName).getVal(), false, 0L
                        , false, urlHelpers.get(featureTask));
                if (StringUtils.isNotEmpty(searchKey) && isContainKey(displayName, searchKey)) {
                    taskMeta.setHighLight(true);
                }
                featureTaskMetas.add(taskMeta);
                panelDTO.add(taskMeta);
            }


        }
        featureTaskItems.setItems(featureTaskMetas);
        featureTaskItems.setSubType(SubTypeEnum.FEATURE_ENGINEERING.getVal());
        panelDTO.add(featureTaskItems);
        return panelDTO;
    }

    private Set<String> getFavouriteOperator(PanelDTO panelDTO) {
        List<TaskMeta> taskMetas = panelDTO.getSearchList();
        Set<String> sets = new HashSet<>();
        for (TaskMeta taskMeta : taskMetas) {
            sets.add(taskMeta.getName());
        }
        return sets;
    }

    public PanelDTO loadPanel(ProjectNameVO vo) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        String searchKey = vo.getSearchName();
        PanelDTO panelDTO = new PanelDTO();

        Set<String> favouriteOperators = this.getFavouriteOperator(panelDTO);
        SubTypeEnum[] subTypes = SubTypeEnum.values();
        Map<String, List<TaskMeta>> maps = new HashMap<>();
        Map<String, Integer> subTypeMap = new HashMap<>();
        for (SubTypeEnum subType : subTypes) {
            String classify = subType.getDesc();
            if (!maps.containsKey(classify)) {
                maps.put(classify, new ArrayList<>());
                subTypeMap.put(classify, subType.getVal());
            }
        }
        //*******************************************清洗/ETL操作******************************************************
        TaskItems etlTaskItems = new TaskItems();
        etlTaskItems.setName(SubTypeEnum.ETL_OPERATE.getDesc());
        List<TaskMeta> etlTaskMeta = new ArrayList<>();
        for (String etl : etls) {
            TaskMeta taskMeta;
            String displayName;
            int subType;
            int algType;
            int taskType;
            if (etl.equals(AlgPyEnum.IMPUTATION_STAT.getName()) || etl.equals(AlgPyEnum.IMPUTATION_MULTI.getName()) ||
                    etl.equals(AlgPyEnum.ANOMALY_KNN.getName()) || etl.equals(AlgPyEnum.ANOMALY_STAT.getName())) {
                AlgPyEnum alg = AlgPyEnum.getEnumByName(etl);
                taskType = TaskTypeEnum.TASK_TYPE_ALGOPY.getVal();
                subType = SubTypeEnum.ETL_OPERATE.getVal();
                algType = alg.getVal();
                displayName = alg.getDesc();
            } else {
                Class<?> c = Class.forName("org.zjvis.datascience.common.etl." + etl);
                Object obj = c.newInstance(); //对应ETL类 必须有无参构建方法
                BaseETL baseETL = (BaseETL) obj;
                displayName = baseETL.getName();
                taskType = TaskTypeEnum.TASK_TYPE_ETL.getVal();
                subType = baseETL.getSubType();
                algType = ETLEnum.valueOf(displayName).getVal();
            }
            if (StringUtils.isEmpty(searchKey) || isContainKey(displayName, searchKey)) {
                taskMeta = new TaskMeta(displayName, taskType,
                        subType, algType, false, 0L
                        , false, urlHelpers.get(etl));
                if (StringUtils.isNotEmpty(searchKey)) {
                    taskMeta.setHighLight(true);
                }
                etlTaskMeta.add(taskMeta);
                panelDTO.add(taskMeta);
            }
        }
        if (StringUtils.isEmpty(searchKey) || isContainKey("清洗", searchKey)
                || isContainKey("clean", searchKey)) {
            TaskMeta taskMetaCleanse = new TaskMeta("清洗", TaskTypeEnum.TASK_TYPE_CLEAN.getVal()
                    , SubTypeEnum.ETL_OPERATE.getVal(), 0,
                    favouriteOperators.contains("清洗"), 0L, true, urlHelpers.get("Clean"));
            if (StringUtils.isNotEmpty(searchKey)) {
                taskMetaCleanse.setHighLight(true);
            }
            etlTaskMeta.add(taskMetaCleanse);
            panelDTO.add(taskMetaCleanse);
        }
        etlTaskItems.setItems(etlTaskMeta);
        etlTaskItems.setSubType(SubTypeEnum.ETL_OPERATE.getVal());
        panelDTO.add(etlTaskItems);

        //***********************************************特征工程**************************************************

        panelDTO = loadFeatureEngAlgo(panelDTO, searchKey);

        //********************************************加载模型库中内容**********************************************

        panelDTO = loadAlgoModel(panelDTO, searchKey, 1L, vo.getProjectId());
        panelDTO = loadAlgoModel(panelDTO, searchKey, 2L, vo.getProjectId());

        // 加载新版算法库内容
        panelDTO = loadAlgorithmModel(panelDTO, searchKey, 1L, vo.getProjectId());

        //***********************************************我的模型**************************************************

        panelDTO = loadMLModel(panelDTO, vo);

        return panelDTO;
    }

    /**
     * 获取已经导出的在项目里的ML model
     *
     * @param panelDTO
     * @param vo
     * @return
     */
    public PanelDTO loadMLModel(PanelDTO panelDTO, ProjectNameVO vo) {
        TaskItems modelTaskItems = new TaskItems();
        modelTaskItems.setName(SubTypeEnum.MLMODEL.getDesc());

        MLModelVO modelInPanel = new MLModelVO();
        modelInPanel.setInPanel(1L);
        modelInPanel.setUserId(vo.getUserId());
        modelInPanel.setProjectId(vo.getProjectId());

        List<TaskMeta> modelTaskMetas = new ArrayList<>();

        List<MLModelDTO> modelDTOSinPanel = mlModelService.queryModelPanel(modelInPanel);
        for (MLModelDTO model : modelDTOSinPanel) {
            if (StringUtils.isEmpty(vo.getSearchName()) || isContainKey(model.getName(), vo.getSearchName())) {
                TaskMeta singleModelTaskMeta = new TaskMeta(model.getName(), TaskTypeEnum.TASK_TYPE_MODEL.getVal(), SubTypeEnum.MLMODEL.getVal(), 7,
                        false, new Long(model.getId()), true, "");
                if (StringUtils.isNotEmpty(vo.getSearchName()) && isContainKey(model.getName(), vo.getSearchName())) {
                    singleModelTaskMeta.setHighLight(true);
                }
                modelTaskMetas.add(singleModelTaskMeta);
                panelDTO.add(singleModelTaskMeta);
            }
        }
        MLModelVO modelvo = new MLModelVO();
        modelvo.setName(vo.getSearchName());
        modelvo.setProjectId(vo.getProjectId());
        modelvo.setUserId(vo.getUserId());
        List<FolderDTO> folderDTOS = mlModelService.getFolders(modelvo);
        for (FolderDTO folder : folderDTOS) {
            if (folder.getSubType() == SubTypeEnum.MLMODEL.getVal()) {
                Long folderId = folder.getId();
                List<MLModelVO> modelsInFolder = mlModelService.queryModelByFolderId(folderId);
                //无搜索或搜索到文件夹后，加入所有文件夹内部模型
                if (StringUtils.isEmpty(vo.getSearchName()) || isContainKey(folder.getName(),
                        vo.getSearchName())) {
                    List<TaskMeta> modelInFolder = new ArrayList<>();
                    Integer unfold = 0;
                    if (modelsInFolder != null) {
                        for (MLModelVO model : modelsInFolder) {
                            String modelName = model.getName();
                            Long modelId = model.getId();
                            TaskMeta folderModelTaskMeta = new TaskMeta(modelName,
                                    TaskTypeEnum.TASK_TYPE_MODEL.getVal(), SubTypeEnum.MLMODEL.getVal(),
                                    7,
                                    false, modelId, true, "");
                            if (StringUtils.isNotEmpty(vo.getSearchName()) && isContainKey(
                                    modelName, vo.getSearchName())) {
                                unfold = 1;
                                folderModelTaskMeta.setHighLight(true);
                            }
                            if (StringUtils.isEmpty(vo.getSearchName())) {
                                panelDTO.add(folderModelTaskMeta);
                            }
                            modelInFolder.add(folderModelTaskMeta);
                        }
                    }
                    TaskMeta singleFolderTaskMeta = new TaskMeta(folder.getName(),
                            TaskTypeEnum.TASK_TYPE_MODEL.getVal(), SubTypeEnum.MLMODEL.getVal(), -1,
                            true, new Long(folder.getId()), true, "",
                            Math.toIntExact(folder.getUnfold()), modelInFolder);
                    if (StringUtils.isNotEmpty(vo.getSearchName()) && isContainKey(folder.getName(),
                            vo.getSearchName())) {
                        singleFolderTaskMeta.setHighLight(true);
                    }
                    singleFolderTaskMeta.setUnfold(unfold);
                    modelTaskMetas.add(singleFolderTaskMeta);
                    panelDTO.add(singleFolderTaskMeta);
                } else {//如果有搜索key且没有与文件夹名相匹配，则尝试匹配文件夹内部模型名称
                    boolean hasModelMatched = false;
                    List<TaskMeta> modelInFolder = new ArrayList<>();
                    if (modelsInFolder != null) {
                        for (MLModelVO model : modelsInFolder) {
                            String modelName = model.getName();
                            Long modelId = model.getId();
                            if (isContainKey(modelName, vo.getSearchName())) {
                                TaskMeta folderModelTaskMeta = new TaskMeta(modelName,
                                        TaskTypeEnum.TASK_TYPE_MODEL.getVal(),
                                        SubTypeEnum.MLMODEL.getVal(), 7,
                                        false, modelId, true, "");
                                folderModelTaskMeta.setHighLight(true);
                                modelInFolder.add(folderModelTaskMeta);
                                panelDTO.add(folderModelTaskMeta);
                                hasModelMatched = true;
                            }
                        }
                    }
                    if (hasModelMatched) {
                        TaskMeta singleFolderTaskMeta = new TaskMeta(folder.getName(),
                                TaskTypeEnum.TASK_TYPE_MODEL.getVal(), SubTypeEnum.MLMODEL.getVal(), -1,
                                true, new Long(folder.getId()), true, "",
                                Math.toIntExact(folder.getUnfold()), modelInFolder);
                        singleFolderTaskMeta.setUnfold(1);
                        modelTaskMetas.add(singleFolderTaskMeta);
                        panelDTO.add(singleFolderTaskMeta);
                    }
                }
            }
        }
        modelTaskItems.setItems(modelTaskMetas);
        modelTaskItems.setSubType(SubTypeEnum.MLMODEL.getVal());
        panelDTO.add(modelTaskItems);
        return panelDTO;
    }

    /**
     * 复制某个panel （现阶段只针对 “我的模型”）下的所有内容，有文件夹的创建文件夹， 不是文件夹的，直接插入到新的项目中
     *
     * @param folder
     */
    public void batchCopy(TaskItems folder, Long newProjectId) {
        List<TaskMeta> items = folder.getItems();
        for (TaskMeta meta : items) {
            if (meta.getIsFolder()) {
                //复制folder 及 里面的内容
                FolderDTO newFolder = folderService.copyIntoNewProject(meta, newProjectId);
                if (meta.getModelInFolder().size() > 0) {
                    //旧的folder中有模型
                    for (TaskMeta model : meta.getModelInFolder()) {
                        MLModelDTO tmpModel = mlModelService.queryMetricsById(model.getId());
                        tmpModel.setId(null);
                        tmpModel.setProjectId(newProjectId);
                        tmpModel.setUserId(JwtUtil.getCurrentUserId());
                        tmpModel.setInvisible(ModelStatusEnum.COPIED.getVal());
                        tmpModel.setFolderId(newFolder.getId());
                        mlModelService.save(tmpModel);
                    }
                }
            } else {
                //仅仅是ML模型，插入到新的项目中
                //invisible -1 代表复制出来的ML model
                MLModelDTO tmpModel = mlModelService.queryMetricsById(meta.getId());
                tmpModel.setId(null);
                tmpModel.setProjectId(newProjectId);
                tmpModel.setUserId(JwtUtil.getCurrentUserId());
                tmpModel.setInvisible(ModelStatusEnum.COPIED.getVal());
                mlModelService.save(tmpModel);
            }
        }
    }

    public void batchCopyModelLoaded(Long userId, Long oldProjectId, Long newProjectId) {
        List<ModelLocalDTO> modelLocalDTOS = modelLocalMapper.queryByProjectId(userId, oldProjectId);
        for (ModelLocalDTO model : modelLocalDTOS) {
            model.setProjectId(newProjectId);
            model.setUserId(JwtUtil.getCurrentUserId());
            modelLocalMapper.save(model);
        }
    }
}
